﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PACKETPARSERMAX20.CORE.DEFINITIONS
{
    public abstract class MovementInfoBase : DefinitionBase
    {
        public override bool Process()
        {
            long current_position = base.Stream.Position;

            ProcessInternal(current_position);

            return Validate();
        }

        public override bool Process(uint pParentOpcode, uint opcode, long pPosition, long pSize)
        {
            base.SetCustomPositionAndSize(pPosition, pSize);
            ProcessInternal(pPosition);

            return ValidateMovementOpcode(pParentOpcode.ToString(), pPosition, pSize);
        }

        private void ProcessInternal(long pCurrentPosition)
        {
            base.Stream.Position = pCurrentPosition;

            // InitLog();
            //Opcode == (int)Opcodes.MSG_MOVE_KNOCK_BACK || 
            //if (Opcode == (int)Opcodes.CMSG_DISMISS_CONTROLLED_VEHICLE)
            //{
            //    bool pause = true;
            //}
            var movementInfo = new MovementInfo();

            if (Opcode == (int)Opcodes.CMSG_MOVE_STOP_SWIM_CHEAT ||
                Opcode == (int)Opcodes.CMSG_MOVE_SPLINE_DONE)
            {
                if (ClientBuild >= 10505)
                {
                    movementInfo.guid = popGuid("guid");
                    //if (LogIt) LogAppendLine("UInt64", "guid", movementInfo.guid, true);
                }
                else
                {
                    movementInfo.guid = Core.PlayerGUID;
                    //if (LogIt) LogAppendLine("UInt64", "guid", movementInfo.guid, false);
                }
            }
            else
            {
                if (Opcode == (int)Opcodes.CMSG_MOVE_FEATHER_FALL_ACK ||
                    Opcode == (int)Opcodes.CMSG_MOVE_NOT_ACTIVE_MOVER ||
                    Opcode == (int)Opcodes.CMSG_MOVE_WATER_WALK_ACK ||
                    Opcode == (int)Opcodes.CMSG_MOVE_SET_CAN_FLY_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_MOVE_ROOT_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_MOVE_UNROOT_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_RUN_SPEED_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_SWIM_SPEED_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_TURN_RATE_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_WALK_SPEED_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_UNK1_SPEED_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_FORCE_UNK2_SPEED_CHANGE_ACK ||
                    Opcode == (int)Opcodes.CMSG_DISMISS_CONTROLLED_VEHICLE
                    )
                {
                    if (ClientBuild >= 10314)
                    {
                        movementInfo.guid = popGuid("guid");
                        //if (LogIt) LogAppendLine("UInt64", "guid", movementInfo.guid, true);
                    }
                    else
                    {
                        movementInfo.guid = ReadUInt64();
                        //if (LogIt) LogAppendLine("UInt64", "guid", movementInfo.guid, false);
                    }
                    if (Opcode == (int)Opcodes.CMSG_MOVE_FEATHER_FALL_ACK ||
                        Opcode == (int)Opcodes.CMSG_MOVE_WATER_WALK_ACK ||
                        Opcode == (int)Opcodes.CMSG_MOVE_SET_CAN_FLY_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_MOVE_ROOT_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_MOVE_UNROOT_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_RUN_SPEED_CHANGE_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_SWIM_SPEED_CHANGE_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_TURN_RATE_CHANGE_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_WALK_SPEED_CHANGE_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_UNK1_SPEED_CHANGE_ACK ||
                        Opcode == (int)Opcodes.CMSG_FORCE_UNK2_SPEED_CHANGE_ACK
                        )
                    {
                        movementInfo.unknown3 = ReadUInt32("unknown3");
                        //if (LogIt) LogAppendLine("UInt32", "unknown3", movementInfo.unknown3);
                    }
                }
                else
                {
                    if (ClientBuild >= 10314)
                    {
                        movementInfo.guid = popGuid("guid");
                        //if (LogIt) LogAppendLine("UInt64", "guid", movementInfo.guid, true);
                    }
                    else
                    {
                        if (base.Direction == 1)
                        {
                            movementInfo.guid = popGuid();
                            //if (LogIt) LogAppendLine("UInt64", "guid", movementInfo.guid, true);
                        }
                        else
                        {
                            movementInfo.guid = Core.PlayerGUID;
                            //if (LogIt) LogAppendLine("UInt64", "guid", movementInfo.guid, false);
                        }
                    }
                }
            }

            movementInfo.movementFlags = (MovementFlags)ReadUInt32();
            //if (LogIt) LogAppendLine("UInt32", "movementFlags", (uint)movementInfo.movementFlags, "", movementInfo.movementFlags.Value.DumpFlags());

            if (ClientBuild >= 9183)
            {
                movementInfo.movementFlags2 = (MovementFlags2)ReadUInt16();// 2.3.0
            }
            else
            {
                movementInfo.movementFlags2 = (MovementFlags2)ReadByte();// 2.3.0
            }

            movementInfo.timeStamp = ReadUInt32();
            //if (LogIt) LogAppendLine("UInt32", "timeStamp", movementInfo.timeStamp);

            movementInfo.positionInfo = ReadCoord4();
            //LogAppend(movementInfo.positionInfo.ToString());


            if ((movementInfo.movementFlags & MovementFlags.MOVEFLAG_ONTRANSPORT) != 0)
            {
                movementInfo.transportInfo = ReadMovementTransport();
                //if (LogIt) LogAppend(movementInfo.transportInfo.ToString());
            }


            if (movementInfo.movementFlags.Value.HasAnyFlag(MovementFlags.MOVEFLAG_SWIMMING | MovementFlags.MOVEFLAG_FLYING) || movementInfo.movementFlags2.Value.HasFlag(MovementFlags2.MOVEFLAG2_ALLOW_PITCHING))
            {
                movementInfo.swimPitch = ReadFloat("swimPitch");
            }

            movementInfo.fallTime = ReadUInt32("fallTime");

            if (movementInfo.movementFlags.Value.HasFlag(MovementFlags.MOVEFLAG_FALLING))
            {
                movementInfo.jumpInfo = ReadMovementJump();
            }

            if (Opcode == 241) //Opcodes.MSG_MOVE_KNOCK_BACK
            {
                if ((movementInfo.movementFlags & MovementFlags.MOVEFLAG_FALLING) > 0)
                {
                    movementInfo.fallInfo = ReadMovementFall();
                }
            }

            if (movementInfo.movementFlags.Value.HasFlag(MovementFlags.MOVEFLAG_SPLINE_ELEVATION))
            {
                movementInfo.splineelevation = ReadFloat("splineelevation");
            }


            if (
            Opcode == (int)Opcodes.MSG_MOVE_SET_RUN_SPEED_CHEAT ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_RUN_SPEED ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_RUN_BACK_SPEED ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_WALK_SPEED_CHEAT ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_WALK_SPEED ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_SWIM_SPEED_CHEAT ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_SWIM_SPEED ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_SWIM_BACK_SPEED ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_ALL_SPEED_CHEAT ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_FLIGHT_SPEED_CHEAT ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_FLIGHT_SPEED ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_FLIGHT_BACK_SPEED ||
            Opcode == (int)Opcodes.MSG_MOVE_SET_TURN_RATE ||
            Opcode == (int)Opcodes.CMSG_MOVE_FEATHER_FALL_ACK ||
            Opcode == (int)Opcodes.CMSG_MOVE_WATER_WALK_ACK ||
            Opcode == (int)Opcodes.CMSG_MOVE_SET_CAN_FLY_ACK ||
            Opcode == (int)Opcodes.CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK ||
            Opcode == (int)Opcodes.CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK ||
            Opcode == (int)Opcodes.CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK ||
            Opcode == (int)Opcodes.CMSG_FORCE_RUN_SPEED_CHANGE_ACK ||
            Opcode == (int)Opcodes.CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK ||
            Opcode == (int)Opcodes.CMSG_FORCE_SWIM_SPEED_CHANGE_ACK ||
            Opcode == (int)Opcodes.CMSG_FORCE_TURN_RATE_CHANGE_ACK ||
            Opcode == (int)Opcodes.CMSG_FORCE_WALK_SPEED_CHANGE_ACK ||
            Opcode == 1231 ||   //CMSG_FORCE_UNK1_SPEED_CHANGE_ACK_DEF
            Opcode == 1233      //CMSG_FORCE_UNK2_SPEED_CHANGE_ACK_DEF
            )
            {
                float speed = ReadSingle("speed");
            }

            if (Opcode == (int)Opcodes.CMSG_MOVE_SPLINE_DONE)
            {
                movementInfo.starttime = ReadUInt32("starttime");
            }

 
            Warning = GetObjectTypeAndName(movementInfo.guid);
            UpdateObjectPosition(movementInfo);

        }
    }
}
